package com.example.demo.controller;

import com.example.demo.model.Music;
import com.example.demo.model.User;
import com.example.demo.service.MusicService;
import com.example.demo.tools.Constant;
import com.example.demo.tools.ResponseBodyMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;


@RestController
@RequestMapping("/music")
public class MusicController {
    // 1.存储路径最好是正斜杠 反斜杠需要穿衣 有的服务器不能够识别两个\\
//    private String SAVE_PATH = "D:/BigDataST/online_music_audio/";//如果想保存到online_music_audio文件下面最后记得还得加正斜杠
    // 2.我们也可以在开发环境中配置存储地址 所以上面的路径我们就注释掉
    // 然后我们通过value注解来 读取配置信息
    @Value("${music.local.path}")
    private String SAVE_PATH;

    @Autowired
    private MusicService musicService;

    // 上传音乐接口
    @RequestMapping("/upload")
    @Transactional // 默认事务传播级别为REQUIRED
    public ResponseBodyMessage<Boolean> insertMusic(@RequestParam String singer,
                                                    @RequestPart("filename") MultipartFile file,
                                                    HttpServletRequest request) {

        // 检查是否登录
        // 验证我们不需要写了  拦截器会帮我们实现


        // 首先获取到上传文件的名称
        String fileNameAndType = file.getOriginalFilename();//文件名.文件类型
        System.out.println("fileNameAndType: " + fileNameAndType);// 打印看效果


//        需要判断该歌曲在数据库中是否存在
//        歌名
        String title = fileNameAndType.substring(0, fileNameAndType.lastIndexOf("."));
        Music music = musicService.select(title, singer);
        if (music != null) {
            return new ResponseBodyMessage<>(-1, "此歌曲已经上传，请重新选择", false);
        }




        // 指定上传音频存储位置
        // 存储路径
        String path = SAVE_PATH + fileNameAndType;
        // 封装
        File dest = new File(path);
        // 如果存储路径不存在 则进行创建
        if (!dest.exists()) {
            dest.mkdir();
        }
        // transferTo参数是一个File类型  注意存储的过程可能会失败 所以他出现编译保存 所以我们需要异常处理
        try {
//            指定上传音频存储位置
            file.transferTo(dest);
//            return new ResponseBodyMessage<>(0, "上传成功", true);//我们需要进行上传数据库了 这行代码就不用了
        } catch (IOException e) {
            // 当异常被trycatch捕获时 要么直接抛出异常 throw e 要么使用下面保存点的方法 触发事务的回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new ResponseBodyMessage<>(-1, "服务器上传失败", false);
        }

//        return new ResponseBodyMessage<Boolean>(-1, "上传失败", false);//我们需要进行上传数据库了 这行代码就不用了


        // 进行数据库上传
        // 1.准备要上传的数据
        //      歌名(放上面进行判断)
//        String title = fileNameAndType.substring(0, fileNameAndType.lastIndexOf("."));

        //      用户id      我们在登录成功之后 创建一个session 将用户信息存入进去 然后再使用request获取
        User user = (User) request.getSession().getAttribute(Constant.USERINFO_SESSION_KEY);
        Integer userid = user.getId();

        //      url     我们将来播放音乐的时候 需要的请求地址 就是播放音乐的时候 发送一个http请求
        String url = "/music/get?path=" + title;// 人为写一个先

        //      time
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        String time = sf.format(new Date());
        // 2.调用MusicService中的insert方法
        Integer ret = musicService.insert(title, singer, time, url, userid);
        if (ret == 1) {
            // 插入成功 上传成功
            // 这里我们应该实现 上传成功后 直接跳转到歌曲列表页
            return new ResponseBodyMessage<>(0, "数据库上传成功！", true);
        }
        return new ResponseBodyMessage<>(-1, "数据库上传失败！", false);
    }


    // 播放音乐
    // byte[]响应中的数据类型
    // byte[] a   响应数组返回出去
    @RequestMapping("/get")
    public ResponseEntity<byte[]> get(String path) {
        // 读取文件路径
        File file = new File(SAVE_PATH + path);
        // 通过readAllBytes 将file路径的文件 读成字节的形式
        byte[] a = null;
        // readAllBytes有可能读取失败 a可能还是null 或者a的length还是为0 所以写成null好一点

        try {
            a = Files.readAllBytes(file.toPath());// 该返回值是byte数组
            // 所以我们还需要再readAllBytes方法执行完成之后 我们继续判断 他是否读取成功
            if (a != null) {
                // 读取成功 数据返回给前端
                return ResponseEntity.ok(a);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 读取失败
        return ResponseEntity.badRequest().build();

    }



    @RequestMapping("/get1")
    public ResponseEntity<byte[]> get1(String path) {
        byte[] a = {97,98,99,100};
        return ResponseEntity.ok(a);
    }




    @RequestMapping("/delete")
    public ResponseBodyMessage<Boolean> delete(@RequestParam(required = false) Integer id) {//required = false如果没有参数必须传
        if (id == null) {
            return new ResponseBodyMessage<>(-1,"无效id",false);
        }
        // 检查删除歌曲是否是数据库中存在
        Music music = musicService.selectMusicById(id);
        if (music == null) {
            return new ResponseBodyMessage<>(-1,"你要删除的歌曲不存在",false);
        }
        // 根据id删除指定歌曲信息(数据库)
        Integer ret = musicService.deleteMusicById(id);
        if (ret == 0) {
            return new ResponseBodyMessage<>(-1,"删除失败",false);
        }
        // 这里需要删除服务器上的歌曲数据(单机的话 是本地盘)
        // 获取名称 如 /music/get?path=汪苏泷 - 晴
        int index = music.getUrl().lastIndexOf("=");
        String fileName = music.getUrl().substring(index+1);//截取歌名 汪苏泷 - 晴
        File file = new File(SAVE_PATH + fileName + ".mp3");
        if (file.delete()) {
            return new ResponseBodyMessage<>(0,"删除成功",true);
        }
        return new ResponseBodyMessage<>(0,"删除失败",false);
    }



    @RequestMapping("/deletesel")
    public ResponseBodyMessage<Boolean> deleteSelMusic(@RequestParam("ids[]") List<Integer> ids) {//required = false如果没有参数必须传
        int sum = 0;
        for (int i = 0; i < ids.size(); i++) {
//            检查删除歌曲是否是数据库中存在
            Music music = musicService.selectMusicById(ids.get(i));
            if (music == null) {
                // 如果歌曲不存在 默认删除成功
                sum += 1;
                continue;
            }
            //        根据id删除指定歌曲信息(数据库)
            int ret = musicService.deleteMusicById(ids.get(i));
            if (ret == 1) {
                // 这里需要删除服务器上的歌曲数据(单机的话 是本地盘)
                // 获取名称 如 /music/get?path=汪苏泷 - 晴
                int index = music.getUrl().lastIndexOf("=");
                String fileName = music.getUrl().substring(index+1);//截取歌名 汪苏泷 - 晴
                File file = new File(SAVE_PATH + fileName + ".mp3");
                if (file.delete()) {
                    sum++;
                    continue;
                }
                // 走到这 服务器文件删除失败了 则需要回滚
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                // 返回删除失败的信息 以及当前成功删除了多少歌
                return new ResponseBodyMessage<>(-1,"批量删除失败！当前删除了" + sum + "首歌",false);
            }
            // 返回删除失败的信息 以及当前成功删除了多少歌
            return new ResponseBodyMessage<>(-1,"批量删除失败！当前删除了" + sum + "首歌",false);
        }
        // 走到这说明 前端要求的歌曲 全部删除
        return new ResponseBodyMessage<>(0,"批量删除成功！当前删除了" + sum + "首歌！",true);
    }


    // 查询音乐模块设置 模糊查询
    // 通过歌名进行模糊查询 这里使用重载
    @RequestMapping("/findmusic")
    public ResponseBodyMessage<List<Music>> findMusic(@RequestParam(required = false) String name) {
        List<Music> list = null;
        if (name == null) {
            list = musicService.findByMusicByName();
        }else {
            list = musicService.findByMusicByName(name);
        }
        return new ResponseBodyMessage<>(0,"查询结果： ",list);
    }
}
